package com.makejl.framework;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.Iterator;
import java.util.Locale;
import java.util.ResourceBundle;

import javax.faces.application.FacesMessage;
import javax.faces.application.FacesMessage.Severity;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

import com.makejl.util.InformationMessage;

public abstract class Handler implements Serializable {

	private static final long serialVersionUID = 8351249507930036407L;

	private Logger logger = Logger.getLogger(this.getClass().getName());

	protected void setGenericMessage(Class<?> clazz, String message) {
		FacesContext facesContext = FacesContext.getCurrentInstance();
		facesContext.addMessage(clazz.getName(), new FacesMessage(
				FacesMessage.SEVERITY_ERROR, message, null));
		/*
		 * Dispatchs to error page mapped on faces-config.xml
		 */
		facesContext.getApplication().getNavigationHandler().handleNavigation(
				facesContext, null, "error");
	}

	protected void setMessage(Class<?> clazz, InformationMessage message) {
		FacesContext facesContext = FacesContext.getCurrentInstance();
		removeMessagesFromFacesContext(clazz, facesContext);

		Locale locale = facesContext.getViewRoot().getLocale();
		ResourceBundle bundle = ResourceBundle.getBundle(
				InformationMessage.BUNDLE_NAME_INFORMATION, locale);

		FacesMessage messageWithParameters = getFacesMessageWithParameters(
				FacesMessage.SEVERITY_INFO, bundle.getString(message
						.getBundleKey()), message.getMessageParameters());
		facesContext.addMessage(clazz.getName(), messageWithParameters);
	}

	private FacesMessage getFacesMessageWithParameters(Severity severity,
			String message, Object[] messageParameters) {
		return new FacesMessage(severity, MessageFormat.format(message,
				messageParameters), null);
	}

	private void removeMessagesFromFacesContext(Class<?> clazz,
			FacesContext facesContext) {
		Iterator<FacesMessage> it = facesContext.getMessages(clazz.getName());
		while (it.hasNext()) {
			it.next();
			it.remove();
		}
	}

	/**
	 * This method realizes the download of certain file based on certain
	 * mimeType
	 * 
	 * @param file
	 *            file to be downloaded
	 * @param mimeType
	 *            if null, "application/octet-stream" will be used
	 * @throws IOException
	 */
	public synchronized void downloadFile(File file, String mimeType)
			throws IOException {
		FileInputStream input = null;
		OutputStream output = null;

		try {
			if (mimeType == null || mimeType.trim().equals("")) {
				mimeType = "application/octet-stream";
			}

			logger.info("MIME TYPE defined: " + mimeType);

			FacesContext facesContext = FacesContext.getCurrentInstance();
			ExternalContext context = facesContext.getExternalContext();

			input = new FileInputStream(file);
			byte[] buf = new byte[(int) file.length()];
			int length;

			HttpServletResponse response = (HttpServletResponse) context
					.getResponse();
			response.setHeader("Content-Disposition", "attachment;filename="
					+ file.getName());
			response.setContentLength((int) file.length());
			response.setContentType(mimeType);

			output = response.getOutputStream();

			while ((length = input.read(buf)) >= 0) {
				output.write(buf, 0, length);
			}

			logger.info("File read.");

			facesContext.responseComplete();
		} finally {
			if (input != null) {
				input.close();
			}

			if (output != null) {
				output.flush();
				output.close();
			}
		}
	}

	/**
	 * Return the ip of the Managed Bean caller
	 * 
	 * @return ip address
	 */
	public String getUserIP() {
		FacesContext context = FacesContext.getCurrentInstance();
		HttpServletRequest request = (HttpServletRequest) context
				.getExternalContext().getRequest();
		return request.getRemoteAddr();
	}

}
